import { readFileSync, writeFileSync } from 'fs';
import parser from '@babel/parser'; // 生成ast抽象语法树
import traverse from '@babel/traverse'; // 遍历抽象语法树，获取内容的
import { transformFromAst } from 'babel-core'; // 这个库有很多处理的方法 我们现在要处理的是  将ESM的模块化语法改成commonjs的语法 https://www.npmjs.com/package/babel-core  查看API网址
import ejs from 'ejs'; // 通过ejs 动态生成文件 https://www.npmjs.com/package/ejs ejs官网 查看动态修改文字部分的方法
import { resolve } from 'path';
let id = 0;

function creayeAssets(filePath) {
  /**
   * 1. 获取文件内容
   * 2. 获取依赖关系
   *    - ast => 抽象语法树（通过它获取文件的信息，就包含依赖信息）
   *      ast在线浏览网址：https://astexplorer.net/
   *    - 通过 @babel/parser 包可以进行转换
   */
  const source = readFileSync(filePath, { encoding: 'utf-8' });

  const ast = parser.parse(source, {
    sourceType: 'module',
  });

  const deps = [];

  traverse.default(ast, {
    // traverse 会去不断的遍历树的内容，这对象里面配置的是一个个回调函数
    ImportDeclaration({ node }) {
      // 当遍历到树的 ImportDeclaration 引入类型时触发的钩子
      let dep = node.source.value; // 导入的文件 如：./foo
      deps.push(dep);
      // console.log(node.source.value);
    },
  });

  // 这里的code 就是将 EMS 的模块话转成 commonjs 的模块化了
  const { code } = transformFromAst(ast, null, {
    presets: ['env'], // 这里写了env 我们需要安装一下 babel-preset-env 这个插件
  });

  return {
    filePath,
    code,
    deps,
    maping: {},
    id: id++,
  };
  // console.log(ast);
}

/**
 * 创建依赖关系图：
 *  文件之间的依赖其实是 图 的一个数据结构，因为涉及到文件之间相互之间的引用
 */
function createGraph() {
  const mainAsset = creayeAssets('./example/main.js');

  const queue = [mainAsset];

  for (const asset of queue) {
    // console.log(111, asset);
    asset.deps.forEach((filePath) => {
      // creayeAssets();
      const temp = creayeAssets(resolve('./example', filePath));
      asset.maping[relativePath] = temp.id;
      queue.push(temp);
    });
  }

  return queue;
}

const graph = createGraph();
// console.log(graph);

// 构建文件的方法
function build(graph) {
  const template = readFileSync('./bundle.ejs', { encoding: 'utf-8' });

  const data = graph.map((assets) => {
    return {
      id: assets.id,
      filePath: assets.filePath,
      code: assets.code,
      maping: assets.maping,
    };
  });

  const code = ejs.render(template, { data }); // 将数据传入 ejs 模板

  console.log(data);

  writeFileSync('./dist/bundle.js', code);

  // console.log(code);
}

build(graph);

// console.log("res", );

// console.log(fs);
